#pragma once

#include "../core/plato_stream.hh"
#include <memory>

namespace plato {

class PlatoStreamImpl : public PlatoStream {
  std::unique_ptr<char[]> buffer_;
  std::size_t read_pos_{0};
  std::size_t write_pos_{0};
  std::size_t size_{0};
  std::size_t max_size_{0};

public:
  PlatoStreamImpl();
  virtual ~PlatoStreamImpl();
  virtual auto write(const char *data, std::size_t size)
      -> std::size_t override;
  virtual auto read(char *data, std::size_t size) -> std::size_t override;
  virtual auto skip(std::size_t size) -> std::size_t override;
  virtual auto copy(char *data, std::size_t size) -> std::size_t override;
  virtual auto available() -> std::size_t override;
  virtual auto clear() -> void override;
  virtual auto data() -> const char * override;
  template <typename T> auto write_type(T t) -> std::size_t {
    return write((const char *)&t, sizeof(T));
  }
  template <typename T> auto read_type(T &t) -> std::size_t {
    return read((char *)&t, sizeof(T));
  }
  virtual auto operator>>(PlatoStream &stream) -> PlatoStream & override;
  virtual auto operator>>(bool &b) -> PlatoStream & override;
  virtual auto operator>>(char &c) -> PlatoStream & override;
  virtual auto operator>>(unsigned char &c) -> PlatoStream & override;
  virtual auto operator>>(std::int16_t &i) -> PlatoStream & override;
  virtual auto operator>>(std::int32_t &i) -> PlatoStream & override;
  virtual auto operator>>(std::int64_t &i) -> PlatoStream & override;
  virtual auto operator>>(std::uint16_t &i) -> PlatoStream & override;
  virtual auto operator>>(std::uint32_t &i) -> PlatoStream & override;
  virtual auto operator>>(std::uint64_t &i) -> PlatoStream & override;
  virtual auto operator>>(float &i) -> PlatoStream & override;
  virtual auto operator>>(double &i) -> PlatoStream & override;
  virtual auto operator<<(const bool b) -> PlatoStream & override;
  virtual auto operator<<(const char c) -> PlatoStream & override;
  virtual auto operator<<(const unsigned char c) -> PlatoStream & override;
  virtual auto operator<<(const std::int16_t i) -> PlatoStream & override;
  virtual auto operator<<(const std::int32_t i) -> PlatoStream & override;
  virtual auto operator<<(const std::int64_t i) -> PlatoStream & override;
  virtual auto operator<<(const std::uint16_t i) -> PlatoStream & override;
  virtual auto operator<<(const std::uint32_t i) -> PlatoStream & override;
  virtual auto operator<<(const std::uint64_t i) -> PlatoStream & override;
  virtual auto operator<<(const float i) -> PlatoStream & override;
  virtual auto operator<<(const double i) -> PlatoStream & override;
  virtual auto operator<<(PlatoStream &stream) -> PlatoStream & override;
};

} // namespace plato
